﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Timers;
using System.Web;

namespace Solution
{
    public class FileLogger
    {
        #region 构造

        public FileLogger()
        {
            _timer = new Timer(60000);
            _timer.Elapsed += TimerElapsed;
            _timer.Start();
            _logs = new Dictionary<string, string>();
        }

        #endregion 构造

        #region 字段

        private readonly Dictionary<string, string> _logs;
        private readonly Timer _timer;

        //日志记录的类型
        private LogType type;
        private bool _busy = false;

        #endregion 字段

        #region 公共方法

        public Dictionary<string, string> GetLogs()
        {
            return _logs;
        }

        public void Log(string group, string message, LogType logType = LogType.Daily)
        {
            lock (this)
            {
                if (_logs.ContainsKey(group))
                {
                    _logs[group] += $"{message}============================================================\r\n\r\n";
                }
                else
                {
                    _logs[group] = message+ "============================================================\r\n\r\n";
                }
                type = logType;
            }
        }

        #endregion 公共方法

        #region 私有方法

        //根据日志类型获取日志文件名，并同时创建文件到期的时间标记
        //通过判断文件的到期时间标记将决定是否创建新文件。
        private string GetFilename()
        {
            DateTime now = DateTime.Now;
            string format = "";
            switch (type)
            {
                case LogType.Daily:
                    format = "yyyyMMdd'.log'";
                    break;
                case LogType.Weekly:
                    format = "yyyyMMdd'.log'";
                    break;
                case LogType.Monthly:
                    format = "yyyyMM'.log'";
                    break;
                case LogType.Annually:
                    format = "yyyy'.log'";
                    break;
            }
            return now.ToString(format);
        }

        private string GetOrCreateFilePath(string group)
        {
            //配置静态路径
            string staticPath = ConfigurationManager.AppSettings["StaticFilePath"];
            if (string.IsNullOrEmpty(staticPath))
            {
                staticPath = System.Environment.CurrentDirectory;  //环境根目录
            }
            //var filePath = $"{@staticPath}\\_logs\\{@group}\\{DateTime.Now.ToString("yyyy-MM-dd")}.log";
            var filePath = $"{@staticPath}\\_logs\\{@group}\\{GetFilename()}";
            var folder = Path.GetDirectoryName(filePath);
            if (!Directory.Exists(folder))
            {
                Directory.CreateDirectory(folder);
            }
            if (File.Exists(filePath) == false)
            {
                File.Create(filePath).Close();
            }
            return filePath;
        }

        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            if (_busy)
            {
                return;
            }
            lock (_logs)
            {
                _busy = true;
                try
                {
                    string filePath = null;
                    foreach (var log in _logs)
                    {
                        if (filePath == null)
                        {
                            filePath = GetOrCreateFilePath(log.Key);
                        }
                        if (string.IsNullOrEmpty(log.Value))
                        {
                            continue;
                        }
                        File.AppendAllText(filePath, log.Value);
                        _logs.Remove(log.Key);
                    }
                }
                catch (Exception)
                {

                }
                _busy = false;
            }
        }

        #endregion 私有方法

        #region Nested 类型

        /// <summary>
        /// 日志类型的枚举
        /// </summary>
        /// <remarks>日志类型枚举指示日志文件创建的方式，如果日志比较多可考虑每天创建一个日志文件
        /// 如果日志量比较小可考虑每周、每月或每年创建一个日志文件</remarks>
        public enum LogType
        {
            /// <summary>
            /// 此枚举指示每天创建一个新的日志文件
            /// </summary>
            Daily,

            /// <summary>
            /// 此枚举指示每周创建一个新的日志文件
            /// </summary>
            Weekly,

            /// <summary>
            /// 此枚举指示每月创建一个新的日志文件
            /// </summary>
            Monthly,

            /// <summary>
            /// 此枚举指示每年创建一个新的日志文件
            /// </summary>
            Annually
        }

        #endregion Nested 类型
    }
}